# 在视频中绘制矩形
import cv2 #导入opencv库，用于视频处理
import glfw #导入glfw库,用于opengl上下文和窗口管理
from OpenGL.GL import *#导入opengl库的所有内容
import numpy as np #导入numpy库，用于数组操作
import time
#路径配置
video_path = "/Users/xclin/Desktop/1.mp4" #输入视频文件的路径
video_out_path = '/Users/xclin/Desktop/1_out.mp4' #输出视频文件的路径
start_time = time.time()
#使用opencv打开视频文件
cap = cv2.VideoCapture(video_path)
#获取视频的宽度和高度
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#获取视频的帧率
fps = cap.get(cv2.CAP_PROP_FPS)
out = cv2.VideoWriter(video_out_path,cv2.VideoWriter_fourcc(*'XVID'),fps,(width,height))

#初始化glfw
if not glfw.init():
    raise Exception("glfw can not be initialized!")
#设置opengl窗口的属性，设置窗口为不可见，用于离屏渲染
glfw.window_hint(glfw.VISIBLE, False)

#创建一个opengl窗口
window = glfw.create_window(640,480,"glfw opengl window",None,None)
if not window:
    glfw.terminate()
    raise Exception("glfw window can not be createdl")
#设置当前窗口上下文
glfw.make_context_current(window)

# 创建帧缓冲区对象 FBO(frame buffer object) 用于离屏渲染
fbo = glGenFramebuffers(1)
# 绑定帧缓冲区对象
glBindFramebuffer(GL_FRAMEBUFFER, fbo)
# 创建纹理对象用于渲染
texture = glGenTextures(1)
# 绑定纹理对象
glBindTexture(GL_TEXTURE_2D, texture)
# 设置纹理的数据存储，此时不传入任何数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, None)
# 将纹理数据存储到帧缓冲区对象中
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0)

# 检查帧缓存是否完整
status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
if status != GL_FRAMEBUFFER_COMPLETE:
    raise Exception("Framebuffer is not complete!")
# 主循环
while not glfw.window_should_close(window):
    # 渲染
    # 获取当前帧
    ret, frame = cap.read()
    if not ret:
        break
    # 将当前帧转换为opengl纹理
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    # 设置视频帧为OpenGL纹理的数据
    glBindTexture(GL_TEXTURE_2D, texture)
    # 将当前帧渲染到opengl纹理中
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, frame.tobytes())

    # 绑定帧缓冲，准备渲染
    glBindFramebuffer(GL_FRAMEBUFFER, fbo)
    # 设置视口大小
    glViewport(0, 0, width, height)
    # 清空颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT)
    # 使用glDrawPixels渲染纹理到帧缓冲区
    glDrawPixels(width, height, GL_RGB, GL_UNSIGNED_BYTE, frame.tobytes())

    # 绘制一个红色矩形
    glBegin(GL_QUADS)
    glColor3f(1.0, 0.0, 0.0)
    glVertex2f(-0.1,-0.1)
    glVertex2f(0.1,-0.1)
    glVertex2f(0.1,0.1)
    glVertex2f(-0.1,0.1)
    glEnd()

    # 捕获渲染帧
    glReadBuffer(GL_COLOR_ATTACHMENT0)

    error = glGetError()
    if error != GL_NO_ERROR:
        print(f"OpenGL Error: {hex(error)}")

    pixels = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)

    # 将像素数据转换回OpenCV的图像格式
    image = np.frombuffer(pixels, dtype=np.uint8).reshape(height, width, 3)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    # 将渲染帧写入输出视频文件
    out.write(image)
    
    #交换缓冲区并轮询IO事件
    glfw.swap_buffers(window)
    glfw.poll_events()

#程序结束，释放资源
cap.release()
out.release()
cv2.destroyAllWindows()
glfw.terminate()

end_time = time.time()
elapsed_time = end_time - start_time
print(f"Elapsed time: {elapsed_time} seconds")